/*
 * Copyright 2013 Robert Peszek.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package fpig.expressions

import fpig.util.CallUtil;
import fpig.common.functions.FpigBase
import groovy.lang.Closure;

/**
 * @author Robert Peszek
 */
class MComprehensionSyntax {
    
	static Closure intoC = 
		CallUtil.toFunction {Map varMap, String varName, Closure fromInput, Closure innerExpr ->
			Closure nested = {z-> 
				varMap[varName] = z;  
				innerExpr()
			}
			
			FpigBase.b(nested) << fromInput() 
	} 


	Closure from(Closure c) {
		c.delegate = vars
		c.resolveStrategy = Closure.DELEGATE_FIRST
		c
	}

	MComprehensionSyntax into(String name) {	    
		Closure newInto = MComprehensionSyntax.intoC(vars, name)
		if(monadicComposition) {
			def oldInto = monadicComposition
			monadicComposition = CallUtil.toFunction {Closure fromInput, Closure innerExpr ->
				oldInto({
					newInto(fromInput, innerExpr) 
				})
			}
		} else {
		   monadicComposition = newInto
		}
		monadicComposition
		this	
	}
	

	def output(Closure content) {
	    if(!monadicComposition)
		   throw new RuntimeException('Invalid comprehension, needs into(x) << from(...) expression')
		   
		content.delegate = vars
		content.resolveStrategy = Closure.DELEGATE_FIRST
		monadicComposition(content)
	}	
	
	static def comprehend(Closure c){
		def comprehension = new MComprehensionSyntax()
		c.delegate = comprehension
		c()
	}
	
	//privates
	def vars = [:]
	Closure monadicComposition = null

	//simply replays property name
	def get(String name){
		name
	}
	
	def leftShift(Closure c) {
		monadicComposition = monadicComposition(c)
	}

}
